/*
 * Improved from chapter6, where AbstractSubject/Subject4ReceiveUpdate/Subject4Functional
 * was re-engineered
 */

package helloscala.practise.chapter13.newClickObserver

abstract class SubjectObserver {
  type S <: Subject
  type O <: Observer

  trait Subject {
    self: S => //#1 self-type annotation, conventionally, 'self' will be used as alias of 'this' instead of direct 'this'
    private var observers = List[O]()
    def addObserver(observer: O) = observers ::= observer
    def notifyAllObservers = {observers foreach (_.receiveUpdate(self))}
  }

  trait Observer {
    def receiveUpdate(subject: S)
  }
}

object ButtonSubjectObserver extends SubjectObserver {
  type S = ObservableButton
  type O = ButtonObserver

  class ObservableButton(override val name: String) extends ButtonWithCallback(name) with Subject {
    override def click = {
      super.click
      notifyAllObservers
    }
  }

  trait ButtonObserver extends Observer {
    def receiveUpdate(button: ObservableButton)
  }
}

class ButtonClickObserver extends ButtonSubjectObserver.ButtonObserver {
  val clicks = new scala.collection.mutable.HashMap[String, Int]()

  import ButtonSubjectObserver.ObservableButton
  override def receiveUpdate(button: ObservableButton) = {
    val count = clicks.getOrElse(button.name, 0) + 1
    clicks.update(button.name, count)
  }

  def countsOfButton(buttonName: String) = clicks.getOrElse(buttonName, -1)
}
//trait AbstractSubject {
//  type Observer
//
//  private var observers = List[Observer]()
//  def addObserver(observer: Observer) = observers ::= observer
//  def notifyAllObservers = {observers foreach notify _}
//  def notify(observer: Observer)
//}
//
//trait Subject4ReceiveUpdate extends AbstractSubject {
//  type Observer = {def receiveUpdate(subject: Any)}
//
//  def notify(observer: Observer) = observer.receiveUpdate(this)
//}
//
//trait Subject4Functional extends AbstractSubject {
//  type Observer = (AbstractSubject) => Unit //higher abstraction than "receiveUpdate(subject)"
//
//  def notify(observer: Observer) = observer(this)
//}

abstract class Widget
trait Clickable {
  def click
}

//trait ObservableClicks extends Clickable with AbstractSubject {
//  abstract override def click = {
//    super.click
//    super.notifyAllObservers
//  }
//}
//
class ButtonWithCallback(val name: String) extends Widget with Clickable {
  def click = {
    //some process in here
  }
}
//
//class SelectiveCounter {
//  var count = 0
//
//  def receiveUpdate(subject: Any) = {
//    count += 1
//  }
//}


